import traceback
from database import cache
import database
import CONSTANTS
import urllib
import binascii
import MySQLdb
import config
import datetime
import time
from datetime import timedelta
import redis
import pymongo
from threading import Thread
import json
from db_wrapper import db_conn


def get_listuser(linkfile):
    list_user = []
    try: 
        if linkfile[:7] == 'http://':
            f = urllib.urlopen(linkfile)
#             platform = f.readline().replace('\r', '').replace('\n', '')
    #         if platform in ['android','ios']:
            user = f.readline()
            while user:
                user = user.replace('\r', '').replace('\n', '')
                if user:
                    user = user.strip()
#                     user = binascii.crc32(user) & 0xffffffff
                    user = str(binascii.crc32(user) & 0xffffffff)
#                     list_user = list_user + user + ','
                    list_user.append(user)
                user = f.readline()
#             list_user = list_user[0:-1] + ')'
            f.close()
        else:
            users = linkfile.split(',')
            for user in users:
                user = user.strip()
#                 user = binascii.crc32(user) & 0xffffffff
                user = str(binascii.crc32(user) & 0xffffffff)
#                 list_user = list_user + user + ','
                list_user.append(user)
#             list_user = list_user[0:-1] + ')'    
#             platform = 'all'
    except:
        traceback.print_exc()
#     if len(list_user)<=2: list_user = '()'
#     if platform:
#         return platform, list_user
#     else:
#         return None, None
    if list_user:
        return list_user
    else:
        return None


#------------------------------------------------------------------------------ 
def get_listtoken(linkfile):
    list_token = []
    try: 
        if linkfile[:7] == 'http://':
            f = urllib.urlopen(linkfile)
            token = f.readline()
            while token:
                token = token.replace('\r', '').replace('\n', '')
                if token:
                    list_token.append(token)
                token = f.readline()
            f.close()
        else:
#             platform = 'all'
            list_token = linkfile.split(',')
            
    except:
        traceback.print_exc()
#         if len(list_token)<=2: list_token = '()'
#     return  platform, list_token   
    if list_token:
        return list_token
    else:
        return None


#------------------------------------------------------------------------------
class NotiCloud:
    def __init__(self):
        self.redis_coon = redis.Redis(host=config.REDIS_SERVER, port=config.REDIS_PORT)
        self.local_redis_conn = redis.Redis()
        # self.mongo_conn = cache()._handmongodb.dbmg
        self.mongo_conn = db_conn.MyMongo().conn.notification
#------------------------------------------------------------------------------ 
    def call_proce(self, fuc, args):
        results = 0
        try:
            v_mysql_conn = database.MySQL_Conn().conn
            v_cursor = v_mysql_conn.cursor()
            if fuc != 'get_next_task':
                print 'func=', fuc
                print 'args=', args 
            v_cursor.callproc(fuc, args)
            results = v_cursor.fetchall()
            v_cursor.close()
            v_mysql_conn.commit()
            v_mysql_conn.close()
        except:
            print fuc, args
            traceback.print_exc()
        return results

    def get_queued_logs(self):
        return self.local_redis_conn.zrange('pushed_log', 0, -1)

    def pop_queued_log(self):
        v_tmp = self.local_redis_conn.zrange('pushed_log', 0, 1)
        self.local_redis_conn.zremrangebyrank('pushed_log', 0, 1)
        if v_tmp:
            return v_tmp[0]
        else:
            return None

    def set_promote(self, app_id, user_name, promote, i_start, i_end):
        self.local_redis_conn.zadd('promote_queue', i_start, ("promotion:" + str(app_id) + ":" + str(user_name), promote, i_end))

    def get_task(self):
        try:
            results = self.call_proce('get_next_task', ())
        except:
            return None
        if results:
            return results[0]
        else:
            return None

    def get_task_options(self, task_id):
        try:
            task_id = int(task_id)
            results = self.call_proce('get_task_options', (task_id))
        except:
            return None
        if results:
            return results[0]
        else:
            return None

    def gt_app_platform(self, args):
        app_name = CONSTANTS.app_id2name[args.get('app_id', 1)]
        platform_name = CONSTANTS.platform_id2name[args.get('platform_id', 2)]
        if platform_name == 'all':
            return None
        results = self.exe_query('SELECT token FROM ' + app_name + ' WHERE platform = \'' + platform_name + '\'')
        if not results:
            return []
        v_queue_platform = str(args.get('task_id', 0)) + "_" + str(args.get('app_id', 1)) + '_' + platform_name + '_' + args['message']
        
        for result in results:
            self.local_redis_conn.zincrby(v_queue_platform, result[0], amount=1)
        return [v_queue_platform]

    def gt_app(self, args):
        v_tmp = []
        v_app_id = args.get('app_id', 1)
        v_msg = args.get('message', '')
        v_task_id = args.get('task_id', 0)
        for v_platform in CONSTANTS.platforms:
            results = self.exe_query('SELECT token FROM ' + CONSTANTS.app_id2name[v_app_id] + ' WHERE platform = \'' + v_platform + '\'')
            if not results:
                continue 
            v_queue = str(v_task_id) + "_" + str(v_app_id) + '_' + v_platform + '_' + v_msg
            self.local_redis_conn.delete(v_queue)
            for result in results:
                self.local_redis_conn.zincrby(v_queue, result[0], amount=1)
            v_tmp.append(v_queue)
        return v_tmp

    def gt_tokens(self, args):
        v_token_link = args.get('tokens', '')
        v_app_id = args.get('app_id', 1)
        v_platform = CONSTANTS.platform_id2name[args.get('platform_id', '')]
        if v_token_link:
            # v_queue=''
            tokens = get_listtoken(v_token_link)
            v_queue = str(args['task_id']) + "_" + str(v_app_id) + '_' + v_platform + '_' + args['message']
            if tokens:
                self.local_redis_conn.delete(v_queue)
                for token in tokens:
                    self.local_redis_conn.zincrby(v_queue, token, amount=1)
                return [v_queue]
            else:
                return None

    def gt_users(self, args):
        v_tmp = []
        try:
            v_app_id = args.get('app_id', 1)
            usernames_link = args.get('usernames', '')
            v_app_name = CONSTANTS.app_id2name[v_app_id]
            if usernames_link:
                # v_queue = ''
                # link den 1 file
                list_user = get_listuser(usernames_link)
                for v_platform in CONSTANTS.platforms:
                    v_tmp_list = list_user
                    v_queue = str(args['task_id']) + "_" + str(v_app_id) + '_' + v_platform + '_' + args['message']
                    self.local_redis_conn.delete(v_queue)
                    while v_tmp_list:
                        # results = 0
                        v_query = ""
                        for user in v_tmp_list[:1000]:
                            v_query = v_query + "select token from " + v_app_name + " where platform = '" + v_platform + "' AND user_id = " + user + " UNION "
                        v_query = v_query[:-7]
                        v_tmp_list = v_tmp_list[1000:]
                        results = self.exe_query(v_query)

                        if results:
                            # self.local_redis_conn.delete(v_queue)
                            for result in results:
                                if result[0]:
                                    self.local_redis_conn.zincrby(v_queue, result[0], amount=1)
                    v_tmp.append(v_queue)
                return v_tmp
        except:
            traceback.print_exc()

    def gt_users_logout(self, args):
        v_tmp = []
        v_task_id = str(args.get('task_id', '1'))
        v_app_id = args.get('app_id', 1)
        self.set_option(v_app_id, v_task_id)
        self.del_members(v_app_id)
        v_time = self.exe_query('SELECT `value` from `task_options` WHERE `task_id`=' + v_task_id + ' AND `key`=\'day\'')
        v_end = self.exe_query('SELECT `value` from `task_options` WHERE `task_id`=' + v_task_id + ' AND `key`=\'end_time\'')
        if v_end:
            v_end = int(v_end[0][0])
        else:
            v_end = int(time.mktime((datetime.date.today() + datetime.timedelta(1)).timetuple()))
        if v_time:
            v_time = int(time.mktime((datetime.datetime.now() - timedelta(days=int(v_time[0][0]))).timetuple()))
        else:
            v_time = 1
            
        try:
            i_platform = CONSTANTS.platform_id2name[args.get('platform_id', 0)]
        except:
            return []
        if i_platform == 'all':
            for v_platform in CONSTANTS.platforms:
                results = self.exe_query('SELECT token, user_name FROM ' + CONSTANTS.app_id2name[v_app_id] + ' WHERE platform = \'' + v_platform+'\' AND last_active > 0 AND last_active <= ' + str(v_time))
                v_queue = v_task_id + "_" + str(args.get('app_id', 1)) + '_' + v_platform + '_' + args['message']
                self.local_redis_conn.delete(v_queue)
                if not results:
                    continue
                for result in results:
                    self.local_redis_conn.zincrby(v_queue, result[0], amount=1)
                    self.set_member(v_app_id, result[1])
                v_tmp.append(v_queue)
        else:
            results = self.exe_query('SELECT token, user_name FROM ' + CONSTANTS.app_id2name[v_app_id] + ' WHERE platform = \'' + i_platform + '\' AND last_active > 0 AND last_active <= ' + str(v_time))
            if not results:
                return v_tmp
            v_queue = v_task_id + "_" + str(args.get('app_id', 1)) + '_' + i_platform + '_' + args['message']
            self.local_redis_conn.delete(v_queue)
            for result in results:
                self.local_redis_conn.zincrby(v_queue, result[0], amount=1)
                self.set_member(v_app_id, result[1])
            v_tmp.append(v_queue)
        self.set_expire(v_app_id, v_end)
        return v_tmp
#------------------------------------------------------------------------------ 
    
    def set_option(self, app_id, task_id):
        v_options = self.exe_query('SELECT `key`, `value` from `task_options` WHERE `task_id`='+task_id)
        v_normed_options = {}
        v_has_start = 0
        v_has_end = 0
        for v_option in v_options:
            v_normed_options[v_option[0]] = v_option[1]
            if v_option[0] == 'start_time':
                v_has_start = 1
            if v_option[0] == 'end_time':
                v_has_end = 1
        if not v_has_start:
            v_normed_options['start_time'] = int(time.time())
        if not v_has_end:
            v_normed_options['end_time'] = int(time.mktime((datetime.date.today() + datetime.timedelta(1)).timetuple()))
        if v_normed_options:
            v_normed_options = json.dumps(v_normed_options)
            self.local_redis_conn.set("promotion:" + str(app_id), v_normed_options)
            
    def del_members(self, app_id):
        self.local_redis_conn.delete('promotion:' + str(app_id) + ":members")

    def set_member(self, app_id, user_name):
        self.local_redis_conn.sadd('promotion:' + str(app_id) + ":members", str(user_name))
    
    def set_expire(self, app_id, end_time):
        self.local_redis_conn.expireat("promotion:" + str(app_id), end_time + 86400)
        self.local_redis_conn.expireat("promotion:" + str(app_id) + ":members", end_time + 86400)

    def exe_query(self, query):
        results = None
        try:
            v_mysql_conn = database.MySQL_Conn().conn
            v_cursor = v_mysql_conn.cursor()
            v_cursor.execute(query)
            results = v_cursor.fetchall()
            v_cursor.close()
            v_mysql_conn.commit()
            v_mysql_conn.close()
        except:
            traceback.print_exc()
            return None
        return results

    def gt_users_login(self, args):
        v_tmp = []
        v_task_id = str(args.get('task_id', '1'))
        v_app_id = args.get('app_id', 1)
        self.set_option(v_app_id, v_task_id)
        try:
            i_platform = CONSTANTS.platform_id2name[args.get('platform_id', 0)]
        except:
            return []
        v_end = self.exe_query('SELECT `value` from `task_options` WHERE `task_id`=' + v_task_id + ' AND `key`=\'end_time\'')
        if v_end:
            v_end = int(v_end[0][0])
        else:
            v_end = int(time.mktime((datetime.date.today() + datetime.timedelta(1)).timetuple()))
        if i_platform == 'all':
            for v_platform in CONSTANTS.platforms:
                results = self.exe_query('SELECT token, user_name FROM ' + CONSTANTS.app_id2name[v_app_id] + ' WHERE platform = \'' + v_platform + '\'')
                if not results:
                    continue
                v_queue = str(args['task_id']) + "_" + str(v_app_id) + '_' + v_platform + '_' + args['message']
                self.local_redis_conn.delete(v_queue)
                for result in results:
                    self.local_redis_conn.zincrby(v_queue, result[0], amount=1)
                    self.set_member(v_app_id, result[1])
                self.local_redis_conn.expireat(v_queue, v_end)
                v_tmp.append(v_queue)
        else:
            results = self.exe_query('SELECT token, user_name FROM ' + CONSTANTS.app_id2name[args.get('app_id', 1)] + ' WHERE platform = \'' + i_platform + '\'')
            if not results:
                return v_tmp
            v_queue = str(args['task_id']) + "_" + str(args.get('app_id', 1)) + '_' + i_platform + '_' + args['message']
            self.local_redis_conn.delete(v_queue)
            for result in results:
                self.local_redis_conn.zincrby(v_queue, result[0], amount=1)
                self.set_member(v_app_id, result[1])
            self.local_redis_conn.expireat(v_queue, v_end)
            v_tmp.append(v_queue)
        self.set_expire(v_app_id, v_end)
        return v_tmp

    def gt_done(self, task_id):
        try:
            v_mysql_conn = database.MySQL_Conn().conn
            v_cursor = v_mysql_conn.cursor()
            v_cursor.callproc('gt_done', (str(task_id),))
            new_status = v_cursor.fetchall()
            v_cursor.close()
            v_mysql_conn.commit()
            v_mysql_conn.close()
            return new_status[0][0]
        except:
            traceback.print_exc()
            return '0'
        
    def update_task_status(self, task_id, status):
        try:
            v_mysql_conn = database.MySQL_Conn().conn
            v_cursor = v_mysql_conn.cursor()
            v_cursor.callproc('update_task_status', (str(task_id), str(status)))
            new_status = v_cursor.fetchall()
            v_cursor.close()
            v_mysql_conn.commit()
            v_mysql_conn.close()
            return new_status[0][0]
        except:
            traceback.print_exc()
            return '0'
#------------------------------------------------------------------------------ 
    funcs_gettoken = {
        1: gt_app,
        2: gt_app_platform,
        3: gt_tokens,
        4: gt_users,
        5: gt_users_logout,
        6: gt_users_login
    }

    def gt_all(self, args):
        func = NotiCloud.funcs_gettoken[args.pop('type')]
        try:
            return func(self, args)
        except:
            traceback.print_exc()

    def fetch_queued_token(self, i_task_queue_name):
        """
            Pop at most 1000 tokens from queue
        """
        v_platform = i_task_queue_name.split('_')[2]
        v_tmp = []
        if v_platform == 'ios':
            v_tmp = cache().get_and_del(i_task_queue_name, 100)
        else:
            v_tmp = cache().get_and_del(i_task_queue_name, 900)
        return v_tmp

    def log(self, i_task_id, i_token, i_user_id, i_send_time, i_status):
        log = {"token": i_token,
               "task_id": i_task_id,
               "user_id": i_user_id,
               "send_time": i_send_time,
               "status": i_status}
        self.mongo_conn['log'].insert(log)
